﻿using System;
using System.Linq;
using System.Reflection;
using MarriageFertility.Helpers;
using MarriageFertility.Mcm;
using TaleWorlds.CampaignSystem;
using TaleWorlds.CampaignSystem.Actions;
using TaleWorlds.CampaignSystem.CharacterDevelopment;
using TaleWorlds.CampaignSystem.Party;

namespace MarriageFertility.Behaviors;

public class ClanLeaderFixBehavior : CampaignBehaviorBase
{
    public override void RegisterEvents()
    {
        CampaignEvents.DailyTickEvent.AddNonSerializedListener(this, DailyTickFixClanLeader);
        CampaignEvents.DailyTickClanEvent.AddNonSerializedListener(this, EnsureValidClanLeader);
        CampaignEvents.DailyTickHeroEvent.AddNonSerializedListener(this,HeroTickEvent);
        CampaignEvents.DailyTickHeroEvent.AddNonSerializedListener(this,FixHeroDeveloper);
        CampaignEvents.DailyTickPartyEvent.AddNonSerializedListener(this,FixDeadHeroParty);
    }
    
    public override void SyncData(IDataStore dataStore)
    {
    }

    private static void FixDeadHeroParty(MobileParty mobileParty)
    {
        if(mobileParty?.LeaderHero==null) return;
        Hero hero = mobileParty.LeaderHero;
        if (hero.HeroState == Hero.CharacterStates.Dead)
        {
            DisbandArmyAction.ApplyByUnknownReason(hero.PartyBelongedTo.Army);
        }
    }

    private static CampaignEventDispatcher GetEventDispatcher()
    {
        return Campaign.Current.GetType()
            .GetProperty(nameof(CampaignEventDispatcher), BindingFlags.Instance | BindingFlags.NonPublic)?
            .GetValue(Campaign.Current) as CampaignEventDispatcher;
    }

    private void DailyTickFixClanLeader()
    {
        if(!MCMSettings.Instance.FixClanLeader) return;
        FixPlayerClanLeader();
        FixKingdomLeader();
        FixClanLeaders(statusCheck: hero => hero.IsDead, action: DestroyClanAction.ApplyByClanLeaderDeath);
        FixClanLeaders(statusCheck: hero => hero.Clan.IsEliminated, action: null);
        FixKingdomRulingClans();
        SetMobilePartyOwnerToMainHero();
    }

    private void FixPlayerClanLeader()
    {
        if (Clan.PlayerClan.Leader != Hero.MainHero)
        {
            Clan.PlayerClan.SetLeader(Hero.MainHero);
        }
    }

    private void FixHeroDeveloper(Hero hero)
    {
        if (hero!=null && hero.IsAlive && hero.HeroDeveloper == null && hero.HeroState!=Hero.CharacterStates.Dead)
        {
            HeroDeveloper value2 = ReflectUtils.CreateInstance<HeroDeveloper>(new object[]
            {
                hero
            });
            ReflectUtils.ReflectFieldAndSetValue("_heroDeveloper", value2, hero);
            hero.Init();
        }
    }

    private void HeroTickEvent(Hero hero)
    {
        if (!hero.HasMet && MCMSettings.Instance.KnowEveryOne)
        {
            hero.SetHasMet();
        }
    }
    
    private void FixKingdomLeader()
    {
        foreach (var kingdom in Kingdom.All.Where(k => !k.IsEliminated && k.Leader.Clan != k.RulingClan))
        {
            kingdom.Leader.Clan = kingdom.RulingClan;
            kingdom.Leader.UpdateHomeSettlement();
        }
    }
    
    private void FixClanLeaders(Func<Hero, bool> statusCheck, Action<Clan> action)
    {
        foreach (var clan in Clan.All.Where(clan =>
                     !clan.IsEliminated && clan.Leader != null && statusCheck(clan.Leader)))
        {
            var newLeader = DetermineNewLeaderForClan(clan) ?? CreateNewClanLeader(clan);
            clan.SetLeader(newLeader);
            GetEventDispatcher()?.OnClanLeaderChanged(clan.Leader, newLeader);
            action?.Invoke(clan);
        }
    }

    private void EnsureValidClanLeader(Clan clan)
    {  
        if(!MCMSettings.Instance.FixClanLeader) return;
        if (clan.IsBanditFaction || clan.Leader?.Clan == clan) return;

        Hero newLeader = clan.Heroes.FirstOrDefault(h => h.IsAlive) ?? CreateNewClanLeader(clan);
        clan.SetLeader(newLeader);
        newLeader.Clan = clan;
    }

    private Hero DetermineNewLeaderForClan(Clan clan)
    {
        return clan.Heroes.FirstOrDefault(hero => hero.IsAlive && hero != clan.Leader);
    }

    private Hero CreateNewClanLeader(Clan clan)
    {
        var newLeader = HeroCreator.CreateSpecialHero(
            CharacterObject.All.Find(
                obj => obj.Culture == clan.Culture && obj.Occupation == Occupation.Lord), clan.Leader.HomeSettlement);
        newLeader.ChangeState(Hero.CharacterStates.Active);
        newLeader.Clan = clan;
        CampaignEventDispatcher.Instance.OnHeroCreated(newLeader);
        return newLeader;
    }

    private void FixKingdomRulingClans()
    {
        foreach (var kingdom in Kingdom.All.Where(k =>
                     k.RulingClan == Clan.PlayerClan && !k.Clans.Contains(Clan.PlayerClan)))
        {
            var newRulingClan = kingdom.Clans.FirstOrDefault(clan => !clan.IsEliminated) ??
                                kingdom.Clans.FirstOrDefault();
            if (newRulingClan != null)
            {
                kingdom.RulingClan = newRulingClan;
            }
        }
    }

    private void SetMobilePartyOwnerToMainHero()
    {
        var mainParty = MobileParty.MainParty?.Party;
        if (mainParty?.Owner != Hero.MainHero)
        {
            mainParty?.SetCustomOwner(Hero.MainHero);
        }
    }
}